package com.tender.jwt;

import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.tender.util.EncodesUtil;
import com.auth0.jwt.JWT;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;

@Component
public class JwtTokenManager {

    @Value("${shiro.jwt.secret}")
    private String jwtSecret = "wb-csd876509";

    /**
     * 签发令牌：
     * jwt字符串包括三个部分
     *
     * 1. header
     *     一般都是固定的，没有什么变化
     *     1.1、当前字符串的类型，一般都是“JWT”
     *     1.2、哪种算法加密，“HS256”或者其他的加密算法
     *
     * 2. payload
     *     一般有四个最常见的标准字段（下面有）
     *     iat：签发时间，也就是这个jwt什么时候生成的
     *     jti：JWT的唯一标识
     *     iss：签发人，一般都是username或者userId
     *     exp：过期时间
     *
     * @param iss       签发人
     * @param ttlMillis 有效时间
     * @param claims    jwt中存储的一些非隐私信息
     */
    public String issuingToken(String iss, long ttlMillis, String sessionId, Map<String, Object> claims) {
        if (claims == null) {
            claims = new HashMap<>();
        }
        long nowMillis = System.currentTimeMillis();

        String base64EncodedSecretKey = EncodesUtil.encodeHex(jwtSecret.getBytes());

        JwtBuilder builder = Jwts.builder()
                .setClaims(claims)
                // jti
                .setId(sessionId)//2. 这个是JWT的唯一标识，一般设置成唯一的，这个方法可以生成唯一标识,此处存储的为【sessionId】,登录成功后回写
                .setIssuedAt(new Date(nowMillis))//1. 这个地方就是以毫秒为单位，换算当前系统时间生成的iat
                .setSubject(iss)//3. 签发人，也就是JWT是给谁的（逻辑上一般都是username或者userId）
                .signWith(SignatureAlgorithm.HS256, base64EncodedSecretKey);//这个地方是生成jwt使用的算法和秘钥
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date exp = new Date(expMillis);//4. 过期时间，这个也是使用毫秒生成的，使用当前时间+前面传入的持续时间生成
            builder.setExpiration(exp);
        }
        return builder.compact();
    }

    /**
     * @param jwtToken 令牌
     * @return
     * @Description 解析令牌
     */
    public Claims decodeToken(String jwtToken) {
        String base64EncodedSecretKey = EncodesUtil.encodeHex(jwtSecret.getBytes());

        // 得到 DefaultJwtParser
        return Jwts.parser()
                // 设置签名的秘钥
                .setSigningKey(base64EncodedSecretKey)
                // 设置需要解析的 jwt
                .parseClaimsJws(jwtToken)
                .getBody();
    }

    public static void main(String[] args) {
        String jwtSecret = "wb-csd876509";
        String jwtToken = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZW5kZXIiLCJleHAiOjE3MTI0NzQxMjksImlhdCI6MTcxMjQ3Mzc2OSwianRpIjoiMWE2YWQ1ZmQtNDYzYy00ZWI3LTg3ZGUtMWQ2NzQ4MjM2MjcxIiwic2hpcm9Vc2VyIjoie1wiZW5hYmxlRmxhZ1wiOlwiWVwiLFwiaWRcIjoxLFwibG9naW5OYW1lXCI6XCJ0ZW5kZXJcIixcIm5pY2tOYW1lXCI6XCLnq7nlsbHlsYXlo6tcIixcInBhc3NXb3JkXCI6XCI3NTJlNWViMTM2MDU5MjhhMGVmOWE5MzNmYzE3NDI2MjJmYTBlNzMxXCIsXCJyZWFsTmFtZVwiOlwi6IuP5LicXCIsXCJyb3dJZFwiOjgyODM1ODcxMjkwODMxNjY3MixcInNhbHRcIjpcImI4YTkzNWI1Yjg4NmEzM2E1NWZlNGQwMTQzMGU2NGZiXCIsXCJzZXhcIjoxLFwic29ydE5vXCI6MSxcInRlbFwiOlwiMTUxNTA1NjU1NTVcIn0ifQ.SgiT2kdPc73k8raigad26AriMsuuGII6ZMZXwEiGt0c";
        JwtTokenManager manager = new JwtTokenManager();
        Claims claims = manager.decodeToken(jwtToken);
        int i = 0;

    }

    /**
     * @param jwtToken 令牌
     * @return
     * @Description 判断令牌是否合法
     */
    public boolean isVerifyToken(String jwtToken) {
        String base64EncodedSecretKey = EncodesUtil.encodeHex(jwtSecret.getBytes());

        // 这个是官方的校验规则，这里只写了一个”校验算法“，可以自己加
        Algorithm algorithm = Algorithm.HMAC256(EncodesUtil.decodeBase64(base64EncodedSecretKey));
        JWTVerifier verifier = JWT.require(algorithm)
                // .withClaim("loginName", "xxxx")
                .build();
        verifier.verify(jwtToken);  // 校验不通过会抛出异常

        // 判断合法的标准：1. 头部和荷载部分没有篡改过。2. 没有过期
        return true;
    }

}
